import requests
import re
import logging
import json

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# --- 1. 配置 ---
# ⚠️ 请确保您的 Cookie 是有效的，否则 API 请求将失败！
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0",
    "Referer": "https://www.bilibili.com/",
    "Cookie": "buvid3=93F12A49-F981-A1BA-0AED-15F0D142A79886204infoc; b_nut=1761553986; _uuid=E10F10E877-9EC2-1273-CD94-9D69B1C38D6D87262infoc; enable_web_push=DISABLE; buvid_fp=1fed7b07500755e95e1beb048c9bb0df; buvid4=56A6D30D-9A98-A987-2B51-47CCDC6B257686954-025102716-utYYOJL/XC9Jt+w4cwQwmg%3D%3D; SESSDATA=60eef209%2C1777170984%2C5291e%2Aa2CjA9mXUMkzvODcTYlLOoWzn1kzivtVrpv1umuWM4oQDoh5dzEPcDb4FI9UsEoqGUDfASVk5peV9ISWVvMEtVUENtd2gxRkZfbjNPZ0haLThpbDFSR2RlUXJPVVF6ZXRUMGRZRHo2emRtTWxRWGdKMmRMZDNjZ1RCRjItbVNJa3hRZkxJemlrTVJ3IIEC; bili_jct=897141e18595e2e15d066305bcfbcde7; DedeUserID=214438039; DedeUserID__ckMd5=2ecf106214ccb391; theme-tip-show=SHOWED; rpdid=|(k))k)~~JYl0J'u~YuYkuYYu; CURRENT_QUALITY=0; theme-avatar-tip-show=SHOWED; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NzcxNzI2ODAsImlhdCI6MTc3NjkxMzQyMCwicGx0IjotMX0.1a3h2C1c5y2oM4a0r3y7U8lQdG9mS5wWfWfQxXh1x8A; bili_ticket_expires=1777172680; b_lsid=87153B3B_19A520B54AA; sid=4qal6z3f; home_feed_column=4; browser_resolution=925-1063; CURRENT_FNVAL=4048; bp_t_offset_214438039=1131616293565235200" 
}

# --- 2. 视频信息获取 (AID/CID) ---

def get_aid_cid(bvid):
    """通过BVID获取AID和CID (取第一个分P的CID)"""
    try:
        # 1. 获取 AID (使用 view API)
        aid_api_url = f"https://api.bilibili.com/x/web-interface/view?bvid={bvid}"
        response = requests.get(aid_api_url, headers=HEADERS, timeout=10)
        response.raise_for_status()
        data = response.json()
        
        if data.get('code') != 0 or not data.get('data'):
            logging.error(f"获取 AID 失败: {data.get('message', '未知错误')}")
            return None
        
        aid = data['data']['aid']
        logging.info(f"成功获取 AID: {aid}")

        # 2. 获取 CID (使用 pagelist API，取第一个)
        cid_api_url = f"https://api.bilibili.com/x/player/pagelist?bvid={bvid}&jsonp=jsonp"
        response = requests.get(cid_api_url, headers=HEADERS, timeout=10)
        response.raise_for_status()
        data = response.json()
        
        if data.get('code') != 0 or not data.get('data') or not data['data']:
            logging.error(f"获取 CID 失败: {data.get('message', '未知错误')}")
            return None
            
        cid = data['data'][0]['cid']
        logging.info(f"成功获取 CID: {cid}")
        
        return {"aid": aid, "cid": cid}
        
    except requests.exceptions.RequestException as e:
        logging.error(f"请求视频信息 API 失败: {e}")
    except (KeyError, IndexError):
        logging.error("从 API 响应中解析 AID/CID 结构出错。")
    return None

# --- 3. 字幕内容提取与清理 ---

def extract_and_clean_subtitle_contents(response_text):
    """解析 V2 响应，获取 AI 字幕 URL (取 ai-zh 或第一个)，请求内容，清理并拼接。"""
    
    try:
        data_v2 = json.loads(response_text)
        if data_v2.get('code') != 0:
            logging.error(f"V2请求返回错误代码: {data_v2.get('code')}, message: {data_v2.get('message')}")
            return None

        subtitles = data_v2.get('data', {}).get('subtitle', {}).get('subtitles')
        if not subtitles:
            logging.warning("视频可能没有字幕。")
            return None
            
        # 优先查找 'ai-zh'，其次是 'zh'，最后使用第一个
        target_sub = next((sub for sub in subtitles if sub.get('lan') in ('ai-zh', 'zh')), subtitles[0])
        relative_url = target_sub.get('subtitle_url')

        if not relative_url:
            logging.error("无法从选定的字幕条目中提取 'subtitle_url'。")
            return None
            
        # 确保 URL 协议完整
        ai_subtitle_url = "https:" + relative_url if relative_url.startswith('//') else relative_url
        logging.info(f"使用字幕 URL: {ai_subtitle_url}")

    except (json.JSONDecodeError, TypeError) as e:
        logging.error(f"解析 V2 响应失败: {e}")
        return None

    # 请求字幕文件内容
    try:
        logging.info("正在请求字幕内容...")
        response_sub = requests.get(ai_subtitle_url, headers=HEADERS, timeout=15)
        response_sub.raise_for_status()
        subtitle_data = response_sub.json()
        
    except requests.exceptions.RequestException as e:
        logging.error(f"请求字幕文件失败: {e}")
        return None
    except json.JSONDecodeError:
        logging.error("解析字幕内容 JSON 失败 (可能不是有效的 JSON 格式)。")
        return None

    # 提取所有 'content' 并清理音乐/歌词标记
    all_contents = []
    # 清理音符标记，如 ♪文本♪
    lyric_pattern = re.compile(r'♪.*♪') 

    for item in subtitle_data.get('body', []):
        content = item.get('content')
        if content:
            # 清理并去除两端空格
            cleaned_content = lyric_pattern.sub('', content).strip()
            if cleaned_content:
                all_contents.append(cleaned_content)
            
    # 使用空格连接所有字幕片段
    return "，".join(all_contents)

# --- 4. 主执行逻辑 ---

if __name__ == "__main__":
    
    video_url = input("请输入 B 站视频链接 (含 BV 号): ")
    
    # 1. 提取 BVID - 优化正则表达式以更通用地匹配链接中的 BV 号
    bvid_match = re.search(r'(BV[a-zA-Z0-9]{10})', video_url)
    
    if not bvid_match:
        logging.error("无效的视频链接，无法提取 BVID。")
    else:
        bvid = bvid_match.group(1)
        # 更新 Referer 以匹配当前视频，这有助于身份验证
        HEADERS["Referer"] = f"https://www.bilibili.com/video/{bvid}"
        
        # 2. 获取 AID 和 CID
        aid_cid_info = get_aid_cid(bvid)
        
        if aid_cid_info:
            aid = aid_cid_info["aid"]
            cid = aid_cid_info["cid"]
                    
            # 3. 构造并请求 V2 API (获取字幕 URL)
            # WBI 接口需要签名，此处直接使用，如果失败，请检查您的 Cookie 是否需要 WBI 认证
            api_url_v2 = f"https://api.bilibili.com/x/player/wbi/v2?aid={aid}&cid={cid}"
            
            try:
                logging.info(f"请求 V2 API: {api_url_v2}")
                response_v2 = requests.get(api_url_v2, headers=HEADERS, timeout=10)
                response_v2.raise_for_status()
                
                # 4. 提取、请求并拼接字幕内容
                final_text = extract_and_clean_subtitle_contents(response_v2.text)
                
                if final_text:
                    print("\n" + "="*50)
                    print("✨ 最终拼接的 AI 字幕文本 ✨")
                    print("="*50)
                    print(final_text)
                    print("="*50)
                    
            except requests.exceptions.RequestException as e:
                logging.error(f"V2 API 请求失败 (检查 Cookie/是否需要 WBI 签名): {e}")